/* * * * * * * * * * * * * * * * * * * * * * * * *
* Description : CRUD基类及事件接口
* Author  : xujiawei@chinahddz.com
* Date    : 2017-5-27
* Version : 1.0
*  * * * * * * * * * * * * * * * * * * * * * * * */
package crud

import (
	"fmt"

	"github.com/chinahdkj/xorm"
	"github.com/go-xorm/builder"
	"gitee.com/dayu1985/framework/logging"
)

type InsertFunc func(bean interface{}) error
type UpdateFunc func(id interface{}, bean interface{}, fields []string) error
type DeleteFunc func(id interface{}, bean interface{}) error
type QueryFunc func(m *CQuery, bean interface{}, beans interface{}) (int64, error)

type ICRUDService interface {
	IActionService
	//查询操作
	Insert(bean interface{}) error
	Update(id interface{}, bean interface{}, fields []string) error
	Delete(id interface{}, bean interface{}) error
	Deletes(id []interface{}, bean interface{}) error
	Get(id interface{}, bean interface{}) error
	Query(m *CQuery, bean interface{}, beans interface{}) (int64, error)
}

type CRUDService struct {
	ActionService
	event *CRUDEvent
}

func NewCRUD(db *xorm.Engine) CRUDService {
	act := NewAction(db)
	crud := new(CRUDService)
	crud.ActionService = act
	return *crud
}

func (s *CRUDService) Insert(bean interface{}) error {

	if s.event != nil {
		s.From().Before(s.event.BeforeInsert).After(s.event.AfterInsert)
	}

	_, err := s.From().Insert(bean)

	return err
}

func (s *CRUDService) Update(id interface{}, bean interface{}, fields []string) error {
	var sess = s.From().Where(s.DB().Quote("_id")+"=?", id)

	if s.event != nil {
		sess.Before(s.event.BeforeUpdate).After(s.event.AfterUpdate)
	}

	if len(fields) == 0 {
		sess.AllCols()
	} else {
		sess.Cols(fields...)
	}

	_, err := sess.Update(bean)
	return err
}

func (s *CRUDService) DeletesOld(id []interface{}, bean interface{}) error {

	n, err := s.From().In("_id", id).Delete(bean)

	logging.Info("已删除: %d", n)

	return err
}

func (s *CRUDService) DeleteOld(id interface{}, bean interface{}) error {

	var sess = s.From().Where(s.DB().Quote("_id")+"=?", id)

	if s.event != nil {

		_, err := sess.Before(s.event.BeforeDelete).After(s.event.AfterDelete).Delete(bean)
		return err
	} else {
		_, err := sess.Delete(bean)
		return err
	}
}

func (s *CRUDService) Deletes(id []interface{}, bean interface{}) error {
	deleteSQL := fmt.Sprintf(`DELETE FROM %s WHERE 1=1`, s.DB().TableInfo(bean).Name)

	var args []interface{}
	conf := builder.In(s.DB().Quote("_id"), id)
	wstr, inarg, _ := builder.ToSQL(conf)
	deleteSQL += " AND " + wstr + " "
	args = append(args, inarg...)

	n, err := s.From().Sql(deleteSQL, args...).Execute()
	logging.Info("已删除: %d", n)

	return err
}

func (s *CRUDService) Delete(id interface{}, bean interface{}) error {
	deleteSQL := fmt.Sprintf(`DELETE FROM %s WHERE 1=1`, s.DB().TableInfo(bean).Name)
	var args []interface{}
	wstr, inarg, _ := builder.ToSQL(builder.Eq{s.DB().Quote("_id"): id})
	deleteSQL += " AND " + wstr + " "
	args = append(args, inarg...)
	if s.event != nil {
		_, err := s.From().Before(s.event.BeforeDelete).After(s.event.AfterDelete).Sql(deleteSQL, args...).Execute()
		return err
	}
	_, err := s.From().Sql(deleteSQL, args...).Execute()

	return err
}

func (s *CRUDService) Query(m *CQuery, bean interface{}, beans interface{}) (int64, error) {
	return m.Query(s.From(), bean, beans)
}

func (s *CRUDService) SqlQuery(sql string, m *CQuery, bean interface{}, beans interface{}) (int64, error) {
	return m.SqlQuery(s.From(), sql, bean, beans)
}

func (s *CRUDService) Get(id interface{}, bean interface{}) error {

	m, isQuery := id.(*CQuery)

	if isQuery {
		sess := s.From()
		m.Filter(sess)
		_, err := sess.Get(bean)
		return err
	} else {
		_, err := s.From().Where(s.DB().Quote("_id")+"=?", id).Get(bean)
		return err
	}
}

type ICRUDEvent interface {
	BeforeInsert(bean interface{})
	AfterInsert(bean interface{})
	BeforeUpdate(bean interface{})
	AfterUpdate(bean interface{})
	BeforeDelete(bean interface{})
	AfterDelete(bean interface{})
}

type CRUDEvent struct {
	ICRUDEvent
}

func NewCRUDEvent(c ICRUDEvent) *CRUDEvent {
	return &CRUDEvent{c}
}

//BatchAction 批量操作对象
type BatchAction struct {
	ID   *string       `json:"id"`   //主ID
	Rows []interface{} `json:"rows"` //批量操作的对象
}
